昨天我們將 MVC 的 C 打造了一個雛形,透過這個雛形我們了解到,靠著 Rack 處理每條 request,搭配 env
裡面的 PATH_INFO
,就可以實現簡單的 Routing
,透過 Routing
來分配任務到相對應的 Controller 和 Action
接著利用 Controller 來 new 一個物件,利用這個 Controller 物件來執行包含的 method,也就是 Action,但實際用起來會發現,還有些問題需要處理,今天就來看看那些問題吧
如果你在 Terminal 上執行 rackup -p 3001
,你在 web server log 會看到上面出現這樣的錯誤訊息
NameError: wrong constant name Favicon.icoController
仔細讀這段錯誤訊息,會發現他的意思是找不到 /favicon.ico
那什麼是 favicon?
Favicon是favorites icon的縮寫,亦被稱為website icon(網頁圖示)、page icon(頁面圖示)或urlicon(URL圖示)。Favicon是與某個網站或網頁相關聯的圖示。網站設計者可以多種方式建立這種圖示,而目前也有很多網頁瀏覽器支援此功能。瀏覽器可以將favicon顯示於瀏覽器的網址列中,也可置於書籤列表的網站名前,還可以放在標籤式瀏覽介面中的頁標題前。
by wiki
其實這段是瀏覽器自動發送的 request,目的是要拿到你網站的 icon,但如果沒有設定的話,反而會一直噴錯誤訊息,這裡我們先用最簡單的方式來處理
# mavericks/lib/mavericks.rb
require "mavericks/version"
require "mavericks/routing"
module Mavericks
class Error < StandardError; end
class Application
def call(env)
# add this code
if env["PATH_INFO"] == '/favicon.ico'
return [404, {'Content-Type' => 'text/html'}, []]
end
klass, act = get_controller_and_action(env)
controller = klass.new(env)
text = controller.send(act)
[200, {'Content-Type' => 'text/html'},
[text]]
end
end
class Controller
attr_reader :env
def initialize(env)
@env = env
end
end
end
利用簡單的檢查,把所有 favicon 的請求都先用 404
來回應 ,等到之後開始建立 view 以後,我們再來處理這個問題
依照目前 Mavericks 的設計,假如在 just_do 那邊瀏覽了還沒有定義的 controller 會發生什麼事情?例如像是 http://127.0.0.1:3001/
# 出現這樣的錯誤訊息
NameError at /
uninitialized constant Controller
因為我們還沒有設定首頁的機制,但其實使用者不應該看到這些畫面,正常來說應該要回應另外製作的 404 提示畫面,像是這樣
by github
那就一樣來修改一下程式碼吧
# mavericks/lib/mavericks.rb
def call(env)
if env["PATH_INFO"] == '/favicon.ico'
return [404, {'Content-Type' => 'text/html'}, []]
end
begin
klass, act = get_controller_and_action(env)
controller = klass.new(env)
text = controller.send(act)
[200, {'Content-Type' => 'text/html'},
[text]]
rescue
[404, {'Content-Type' => 'text/html'},
['This is a 404 page!!']]
end
end
接著在瀏覽一次 http://127.0.0.1:3001/
This is a 404 page!!
哦!現在我們有 404 page 了,雖然還只是個字串,但至少不會再隨便噴錯給使用者看了
我們暫時解決了噴錯的問題,但我們還是得讓開發者可以自訂首頁才對,問題來了,像http://127.0.0.1:3001/
這樣的網址結構,既沒有 Controller,也沒有 Action 可以解析,那該怎麼辦?沒關係,我們可以利用前面提到的 PATH_INFO
,來分辨這個 request 是不是對 'http://127.0.0.1:3001/' 這頁做 request
讓我們修改並整理一下程式碼
# mavericks/lib/mavericks.rb
class Application
def call(env)
return favicon if env["PATH_INFO"] == '/favicon.ico'
return index if env["PATH_INFO"] == '/'
begin
klass, act = get_controller_and_action(env)
controller = klass.new(env)
text = controller.send(act)
[200, {'Content-Type' => 'text/html'},
[text]]
rescue
[404, {'Content-Type' => 'text/html'},
['This is a 404 page!!']]
end
end
private
def index
[200, {'Content-Type' => 'text/html'}, ['This is a index page']]
end
def favicon
return [404, {'Content-Type' => 'text/html'}, []]
end
end
所以現在的情況是,開發者沒有自訂首頁的話,我們就會給他一個預設首頁訊息,那如果開發者想要自訂首頁內容呢?那我們可以再修改一下程式碼,讓 Mavericks 預設可以去尋找有沒有 HomeController
# mavericks/lib/mavericks.rb
class Application
def call(env)
return favicon if env["PATH_INFO"] == '/favicon.ico'
# 加上 env 變數
return index(env) if env["PATH_INFO"] == '/'
begin
klass, act = get_controller_and_action(env)
controller = klass.new(env)
text = controller.send(act)
[200, {'Content-Type' => 'text/html'},
[text]]
rescue
[404, {'Content-Type' => 'text/html'},
['This is a 404 page!!']]
end
end
private
# 如果開發者有 HomeController,就執行 HomeController#index
def index(env)
begin
home_klass = Object.const_get('HomeController')
controller = home_klass.new(env)
text = controller.send(:index)
[200, {'Content-Type' => 'text/html'}, [text]]
rescue NameError
[200, {'Content-Type' => 'text/html'}, ['This is a index page']]
end
end
def favicon
return [404, {'Content-Type' => 'text/html'}, []]
end
end
太好了,現在開發者可以替購物車自訂首頁內容了,先建立 HomeController#index
# just_do/app/controllers/home_controller.rb
class HomeController < Mavericks::Controller
def index
'just do index page'
end
end
別忘了要去 config 檔案裡面 require 新加入的 HomeController
# just_do/config/application.rb
require 'mavericks'
$LOAD_PATH << File.join(File.dirname(__FILE__), "..", "app", "controllers")
require 'tasks_controller'
# 加上這行
require 'home_controller'
module JustDo
class Application < Mavericks::Application
end
end
然後再一次瀏覽 http://127.0.0.1:3001/
會出現自訂的訊息
just do index page
酷!
雖然 Mavericks 已經有 Controller 可以使用了,也可以依照不同的頁面加上相對應的 Action,但開發起來有點麻煩耶,每次只要新增一個新的 Controller 檔案,就要自己手動加上 require,我記得 Rails 都不用呀...
嗯...好問題,Rails 的 Autoload 機制的確是一個相當方便的功能,只要新增檔案以後,連伺服器都不用重新開啟,網頁重整一下就好了,這也是 Rails 開發速度會那麼快的原因之一,既然是很重要的功能,那明天就來想辦法加到 Mavericks 上吧!